module ysyx_050369_icache (
	input 			    clk,    // Clock
	input 			    rst,  // Asynchronous reset active low
    input [31:0] 	    pc,
    output  		    pc_stop,
    input               i_stop,
    input			    fulsh,
    input               dc_fdone,
	input			    i_pre_jump,
	input	[31:0]      i_pre_pc,
    output    [31:0]    o_inst,
	output reg[31:0]    o_pc,
	output reg[31:0]    o_pre_pc,
    output reg          o_pre_jump,

`ifdef ysyx_050369_SOC
    output [5:0]    io_sram4_addr,
	output          io_sram4_cen,
	output          io_sram4_wen,
	output [127:0]  io_sram4_wmask,
	output [127:0]  io_sram4_wdata,
	input [127:0]   io_sram4_rdata,
	output [5:0]    io_sram5_addr,
	output          io_sram5_cen,
	output          io_sram5_wen,
	output [127:0]  io_sram5_wmask,
	output [127:0]  io_sram5_wdata,
	input [127:0]   io_sram5_rdata,
    output [5:0]    io_sram6_addr,
	output          io_sram6_cen,
	output          io_sram6_wen,
	output [127:0]  io_sram6_wmask,
	output [127:0]  io_sram6_wdata,
	input [127:0]   io_sram6_rdata,
    output [5:0]    io_sram7_addr,
	output          io_sram7_cen,
	output          io_sram7_wen,
	output [127:0]  io_sram7_wmask,
	output [127:0]  io_sram7_wdata,
	input [127:0]   io_sram7_rdata,
`endif
    input  [127:0]  cache_wdata,
    input           cache_wen,
    output          axi_read,
    output          unbrust,
    output [31:0 ]  ic_raddr

);

wire [5:0]  idx;
wire [21:0] tag;
////////////////////////////////
//cache中的信息包含
///////////////////////////////
reg [22:0] channl_tag  [63:0][3:0];
reg [1:0]  count       [63:0];
///////////////////////////////
// ///////////////////////////////
wire[3:0]   wen;
reg [3:0]   hit;
reg 		de_stop;
reg [31:0]  de_pc;
always @(posedge clk ) begin
	if(rst)begin
		de_stop <= 'b0;
		de_pc <= 'b0;
	end
	else begin
		de_stop <= i_stop || pc_stop;
		de_pc   <= o_pc;
	end
end


///////////////////////////////////
//////第一个周期的数据处理
///////////////////////////////////
wire channl0_hit,channl1_hit,channl2_hit,channl3_hit;
wire data_hit;
// wire axi_read;
wire [127:0] inst_data_cache;
wire [31:0] inst_data_temp;
assign idx         = pc[9:4];//16
assign tag         = pc[31:10];
assign channl0_hit = channl_tag[idx][0]=={1'b1,tag} ;
assign channl1_hit = channl_tag[idx][1]=={1'b1,tag} ;
assign channl2_hit = channl_tag[idx][2]=={1'b1,tag} ;
assign channl3_hit = channl_tag[idx][3]=={1'b1,tag} ;
assign data_hit    = channl0_hit||channl1_hit||channl2_hit||channl3_hit;

assign wen[0]	   = (cache_wen&&(count[idx]==2'b00))?1'b0:1'b1;
assign wen[1]	   = (cache_wen&&(count[idx]==2'b01))?1'b0:1'b1;
assign wen[2]	   = (cache_wen&&(count[idx]==2'b10))?1'b0:1'b1;
assign wen[3]	   = (cache_wen&&(count[idx]==2'b11))?1'b0:1'b1;
integer  i;
always @(posedge clk ) begin
	if (rst || dc_fdone) begin
		for (i =0 ; i<64 ; i++) begin
			channl_tag[0][i] <= 23'b0;
			channl_tag[1][i] <= 23'b0;
			channl_tag[2][i] <= 23'b0;
			channl_tag[3][i] <= 23'b0;
			count        [i] <= 2'b0;
		end
	end
	else begin
		if (cache_wen) begin
			channl_tag[idx][count[idx]] <= {1'b1,tag};
			count [idx]					<= count[idx] + 1;
		end
	end
end


///////////////////////////////////
//////第二个周期的数据处理
///////////////////////////////////
reg [31:0] de_inst;
// always @(*) begin
//     case (hit)
//          4'b0001:inst_data_temp = {io_sram4_rdata>> {o_pc[3:0],3'b0}} [31:0];
//          4'b0010:inst_data_temp = {io_sram5_rdata>> {o_pc[3:0],3'b0}} [31:0];
//          4'b0100:inst_data_temp = {io_sram6_rdata>> {o_pc[3:0],3'b0}} [31:0];
//          4'b1000:inst_data_temp = {io_sram7_rdata>> {o_pc[3:0],3'b0}} [31:0];
//         default: inst_data_temp = 'b0;
//     endcase
// end
assign inst_data_cache =hit[0] ? io_sram4_rdata :
                        hit[1] ? io_sram5_rdata :
                        hit[2] ? io_sram6_rdata :
                        hit[3] ? io_sram7_rdata : 'b0;

						
// assign inst_data_temp  = inst_data_cache >> {o_pc[3:0],3'b0};
assign inst_data_temp = (~o_pc[3] && ~o_pc[2]) ?  inst_data_cache[31:0]:
						(~o_pc[3] &&  o_pc[2]) ?  inst_data_cache[63:32]:
						( o_pc[3] && ~o_pc[2]) ?  inst_data_cache[95:64]:
												  inst_data_cache[127:96];

always @(posedge clk ) begin
	if(rst||fulsh) begin
		o_pc      		<= 'b0;
		o_pre_jump		<= 'b0;
		o_pre_pc  		<= 'b0;
		de_inst 		<= 'b0;
		hit				<= 'b0;
	end else begin
        if (~i_stop  ) begin
            o_pc     	<= pc;
			hit			<= {channl3_hit,channl2_hit,channl1_hit,channl0_hit};
			/////////////////////////////
			o_pre_jump  <= i_pre_jump;
			o_pre_pc    <= i_pre_pc  ;
        end
		if (~de_stop) begin
			de_inst <= inst_data_temp;
        end
        
	end
end
wire   pc_update;
assign pc_update = de_pc!=o_pc;
assign pc_stop   = (pc!=0) && (~data_hit) || cache_wen;
assign o_inst    = pc_update?inst_data_temp:de_inst ;
assign axi_read  = ~data_hit && (pc != 'b0); 
assign ic_raddr  = pc; 
assign unbrust   = ~pc[31];  



`ifndef ysyx_050369_SOC
    wire  [5:0]    io_sram4_addr;	
	wire           io_sram4_cen	;
	wire           io_sram4_wen	;
	wire  [127:0]  io_sram4_wmask;
	wire  [127:0]  io_sram4_wdata;
	wire [127:0]   io_sram4_rdata;
	wire  [5:0]    io_sram5_addr;
	wire           io_sram5_cen;
	wire           io_sram5_wen;
	wire  [127:0]  io_sram5_wmask;
	wire  [127:0]  io_sram5_wdata;
	wire [127:0]   io_sram5_rdata;
    wire  [5:0]    io_sram6_addr;
	wire           io_sram6_cen;
	wire           io_sram6_wen;
	wire  [127:0]  io_sram6_wmask;
	wire  [127:0]  io_sram6_wdata;
	wire [127:0]   io_sram6_rdata;
    wire  [5:0]    io_sram7_addr;
	wire           io_sram7_cen;
	wire           io_sram7_wen;
	wire  [127:0]  io_sram7_wmask;
	wire  [127:0]  io_sram7_wdata;
	wire [127:0]   io_sram7_rdata;
   S011HD1P_X32Y2D128_BW Icache0(
        .Q      (io_sram4_rdata), 
        .CLK    (clk), 
        .CEN    (io_sram4_cen), 
        .WEN    (io_sram4_wen), 
        .BWEN   (io_sram4_wmask), 
        .A      (io_sram4_addr), 
        .D      (io_sram4_wdata)
    );
   S011HD1P_X32Y2D128_BW Icache1(
        .Q      (io_sram5_rdata), 
        .CLK    (clk), 
        .CEN    (io_sram5_cen), 
        .WEN    (io_sram5_wen), 
        .BWEN   (io_sram5_wmask), 
        .A      (io_sram5_addr), 
        .D      (io_sram5_wdata)
    );
   S011HD1P_X32Y2D128_BW Icache2(
        .Q      (io_sram6_rdata), 
        .CLK    (clk), 
        .CEN    (io_sram6_cen), 
        .WEN    (io_sram6_wen), 
        .BWEN   (io_sram6_wmask), 
        .A      (io_sram6_addr), 
        .D      (io_sram6_wdata)
    );
   S011HD1P_X32Y2D128_BW Icache3(
        .Q      (io_sram7_rdata), 
        .CLK    (clk), 
        .CEN    (io_sram7_cen), 
        .WEN    (io_sram7_wen), 
        .BWEN   (io_sram7_wmask), 
        .A      (io_sram7_addr), 
        .D      (io_sram7_wdata)
    );
`endif 
// assign io_sram4_addr    = wen[0]?data_idx:idx;
assign io_sram4_addr    = idx;
assign io_sram4_cen     = 1'b0; 
assign io_sram4_wen     = wen[0];
assign io_sram4_wmask   = 'b0; 
assign io_sram4_wdata   = cache_wdata;  
assign io_sram5_addr    = idx;
assign io_sram5_cen     = 1'b0;
assign io_sram5_wen     = wen[1];
assign io_sram5_wmask   = 'b0;   
assign io_sram5_wdata   = cache_wdata;   
assign io_sram6_addr    = idx;
assign io_sram6_cen     = 1'b0; 
assign io_sram6_wen     = wen[2];
assign io_sram6_wmask   = 'b0;  
assign io_sram6_wdata   = cache_wdata;  
assign io_sram7_addr    = idx;
assign io_sram7_cen     = 1'b0;
assign io_sram7_wen     = wen[3];
assign io_sram7_wmask   = 'b0; 
assign io_sram7_wdata   = cache_wdata;  

endmodule